#include "Simulator.h"

#include <fstream>
#include <iostream>
#include <string>
using namespace std;

// ask the user for the data needed to create the simulation
void Simulator::collect_data(string filename) {
	char ans;
	char skew[30], helper[3];
	int i, j, t, sum, s;
	nof_time_slices = 0;
	nof_luns = 0;
	extents_per_lun = 0;
	lun_skew = new int[6];
	ios_per_slice = 0;
	lun_priorities = new double[nof_luns];
	lun_read_percent = new int[nof_luns];

	ofstream myfile;
	myfile.open(filename);
	myfile.close();

	cout << "Hello. Welcome to the Simulator! Please enter the following parameters:\n" << endl;
	while (nof_time_slices <= 0) { 
		cout << "Number of time slices: " << endl;
		cin >> nof_time_slices;
		cout << endl;
	}
	while (nof_luns <= 0) {
		cout << "Number of luns: " << endl;
		cin >> nof_luns;
		cout <<  endl;
	}
	while (extents_per_lun <= 0) {
		cout << "Number of extents per lun: " << endl;
		cin >> extents_per_lun;
		cout <<  endl;
	}

	cout << "Priority per Lun? Y/N" << endl;
	cin >> ans;
	cout <<  endl;

	if (ans == 'Y' || ans == 'y') {
		for (i = 0; i < nof_luns; i++) {
			cout << "Priority of Lun " << i + 1 << ": " << endl;
			cin >> lun_priorities[i];
			cout <<  endl;
		}
	}
	else {
		for (i = 0; i < nof_luns; i++) {
			lun_priorities[i] = 1;
		}
	}

	for (t = 0; t < nof_time_slices; t++) {
		cout << "Starting Time Slice " << t + 1 << endl;
		while (ios_per_slice <= 0) {
			cout << "Number of IOs for time slice " << t + 1 << ": " << endl;
			cin >> ios_per_slice;
			cout <<  endl;
		}
		sum = 0;
		while (sum != 100) {
			sum = 0;
			for (j = 0; j < nof_luns; j++) {
				if ((j + 1) == nof_luns) {
					if (100 - sum > 0) {
						cout << "Percent left: " << 100 - sum << ". Use for last lun? Y/N" << endl;
						cin >> ans;
						cout <<  endl;
						if (ans == 'y' || ans == 'Y') {
							lun_read_percent[j] = 100 - sum;
							sum += lun_read_percent[j];
						}
						else {
							cout << "Starting Over" << endl;
						}
					}
					else {
						cout << "Percentages incorrect. Starting Over. " << endl;
					}
				}
				else {
					cout << "Percent of read-miss for Lun " << j + 1 << ": " << endl;
					cin >> lun_read_percent[j];
					cout <<  endl;
					sum += lun_read_percent[j];
				}
			}
		}
		
		for (i = 0; i < nof_luns; i++) {
			sum = 0;
			while (sum < 200) {
				sum = 0;
				cout << "Skew for Lun " << i + 1 << " [x,x][x,x][x,x]: " << endl;
				cin >> skew;
				cout <<  endl;
				s = 1;
				for (j = 0; j < 6; j++) {
					helper[0] = skew[s];
					s++;
					if (skew[s] == ',') {
						helper[1] = 0;
					}
					else {
						helper[1] = skew[s];
						helper[2] = 0;
						s++;
					}
					lun_skew[j] = atoi(helper);
					sum += lun_skew[j];
					s++;
					if (j%2 != 0) {
						s++;
					}
				}
			}
			simulate(filename, i);
		}
		time +=3600;
		ios_per_slice = 0;
	}
	cout << "Data Ready" <<endl;

	delete [] lun_priorities;
	delete [] lun_skew;
	delete [] lun_read_percent;
}

// use user input to create a simulated trace file
void Simulator::simulate(string filename, int lun) {
	int n, k, extent, e;
	double i, j; 

	int io = (ios_per_slice / (nof_luns * extents_per_lun));
	int total_lun_ios = ((ios_per_slice * lun_read_percent[lun]) / 100);

	ofstream myfile;
	myfile.open(filename, ios::ate | ios::app);

	extent = 0; 
	for (k = 0; k < 6; k = k + 2) {
		j = ((double)(lun_skew[k] * extents_per_lun) / 100); /* number of extents */
		i = ((double)(lun_skew[k+1] * total_lun_ios) / 100); /* number of ios for chosen extents */ 
		
		if (j < 1) {
			e = 1;
		}
		else {
			e = (int)(j + 0.5);
		}

		io = (int)(i / e);

		// write line for each extent
		for (n = 0; n < e; n++) {
			myfile << time << " SUMM FA " << lun + 1 << " " << extent * length << " " << length << " ";
			myfile << io << " 0 0 0 0 0 0 0 0 0 0 " << endl;
			extent++;

			cout << "extent: " << extent << endl;
		}
	}
	
	myfile.close();
}

// create a simulated trace file using configuration file given
void Simulator::simulateParsed(string output, int nof_timeslices, int nof_IOs, int nof_luns, int nof_extents, int* skew, double lun_priority) {
	double i, j;
	int e, extent, final_io;
	int io = (nof_IOs / (nof_luns * nof_extents));

	ofstream myfile;
	myfile.open(output, ios::ate | ios::app);

	for (int q = 0; q < nof_timeslices; q++){
		extent = (q%nof_extents);
		for (int lun = 1; lun <= nof_luns; lun++){
			for (int k = 0; k < 6; k = k + 2) {
				j = ((double)(skew[k] * nof_extents) / 100); /* number of extents */
				i = ((double)(skew[k+1] * io) / 100); /* number of ios for chosen extents */ 
		
				if (j < 1) {
					e = 1;
				}
				else {
					e = (int)(j + 0.5);
				}

				final_io = (int)(i / e);

				for (int n = 0; n < e; n++) {
					myfile << (time+(3600*q)) << " SUMM FA " << lun << " " << (extent * length) << " " << length << " ";
					myfile << final_io << " 0 0 0 0 0 0 0 0 0 0 " << endl;
					extent++;
				}
			}
		}
	}

}

// parse configuration file given
void Simulator::parse_data(string input, string output) {
	string header;
	char line[128];
	ifstream in_file;
	ofstream out_file;
	size_t found;
	int nof_timeslices;
	int nof_IOs;
	int nof_luns;
	int nof_extents;
	int* skew;
	double lun_priority;
	int search;

	in_file.open(input);
	if ( !in_file.is_open() ) {
		cout << "ERROR: could not open input file" << endl;
		return;
	}


	out_file.open(output);
	if ( !out_file.is_open() ) {
		cout << "ERROR: could not open output file" << endl;
		return;
	}
	out_file.close();

	nof_timeslices = 0;
	while (!in_file.eof())
    {
		search = 1;
		getline(in_file, header);
		while ((header.length() == 0) && (!(in_file.eof()))){
			getline(in_file, header);
		}
		if (in_file.eof()){
			return;
		}
		else if (header.at(0) != '#') {
			cout << "ERROR: file format incorrect, header = " << header << endl;
			return;
		}

		if (search == 1){
			found = header.find("number_of_timeslices");
			if (found != string::npos) {
				in_file >> line;	
				nof_timeslices = atoi(line);
				if (nof_timeslices <= 0) {
					cout << "ERROR: incorrect number of timeslices" << endl;
					return;
				}
				search = 0;
			}
		}

		if (search == 1){
			found = header.find("number_of_IOs");
			if (found != string::npos) {
				in_file >> line;	
				nof_IOs = atoi(line);
				if (nof_IOs <= 0) {
					cout << "ERROR: incorrect number of IOs" << endl;
					return;
				}
				search = 0;
			}
		}

		if (search == 1){
			found = header.find("number_of_luns");
			if (found != string::npos) {
				in_file >> line;	
				nof_luns = atoi(line);
				if (nof_luns <= 0) {
					cout << "ERROR: incorrect number of luns" << endl;
					return;
				}

				in_file >> line;	
				nof_extents = atoi(line);
				if (nof_extents <= 0) {
					cout << "ERROR: incorrect number of extents" << endl;
					return;
				}

				in_file >> line;
				skew = new int[6];
				
				int s = 1;
				char temp[3];
				for (int i = 0; i < 6; i += 2) {
					temp[1] = 0;
					temp[0] = line[s];
					s++;
					if (line[s] != ',') {
						temp[1] = line[s];
						temp[2] = 0;
						s++;
					}
					skew[i] = atoi(temp);
					s++;
					temp[1] = 0;
					temp[0] = line[s];
					s++;
					if (line[s] != ']') {
						temp[1] = line[s];
						temp[2] = 0;
						s++;
					}
					skew[i+1] = atoi(temp);
					s+=2;
				}
			
				in_file >> line;	
				lun_priority = atof(line);
				if (lun_priority <= 0) {
					cout << "ERROR: incorrect lun priority" << endl;
					return;
				}

				simulateParsed(output, nof_timeslices, nof_IOs, nof_luns, nof_extents, skew, lun_priority);
				search = 0;
			}
		}

		if (search == 1){
			found = header.find("end_of_lun_groups");
			if (found != string::npos) {
				in_file >> line;
				time += 3600 * nof_timeslices;
				nof_timeslices = 0;
			}
		}
	}

	delete [] skew;

	in_file.close();
}
